﻿using System;
using System.Net;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Resources;
using System.Windows.Markup;
using System.IO;
using System.Windows.Threading;

using DragDraw.UserService;
using DragDraw;

namespace DragDraw.Util
{
    /// <summary>
    /// 逻辑操作管理器，处理引擎的操作流程，定期更新服务数据
    /// </summary>
    public class OperationManager :
        IFileServiceListener,
        IFriendServiceListener,
        IMessageServiceListener,
        IUserServiceListener,
        ISpaceServiceListener,
        IWidgetServiceListener,
        ISystemServiceListener
    {
        #region properties
        /// <summary>
        /// 指示系统是否初始化完毕
        /// </summary>
        public bool Ready { get { return m_ready; } }
        /// <summary>
        /// 系统设定
        /// </summary>
        public SystemSetting Setting { get { return m_setting; } }
        /// <summary>
        /// 我的用户信息
        /// </summary>
        public UserInfo MyUserInfo { get { return m_myUserInfo; } }
        /// <summary>
        /// 我的空间信息
        /// </summary>
        public SpaceInfo MySpace { get { return m_mySpace; } }
        /// <summary>
        /// 我的好友列表
        /// </summary>
        public List<string> MyFriends { get { return m_myFriends; } }
        /// <summary>
        /// 我的信息
        /// </summary>
        public List<SysMessage> MyMessages { get { return m_myMessages; } }
        /// <summary>
        /// 目前浏览的空间信息
        /// </summary>
        public SpaceInfo CurrentSpace { get { return m_currentSpace; } }
        /// <summary>
        /// 目前浏览空间的小工具信息，以WidgetID为键值
        /// </summary>
        public Dictionary<int, WidgetInfo> CurrentWidgets { get { return m_currentWidgets; } }
        /// <summary>
        /// WidgetID到库信息的词典
        /// </summary>
        public Dictionary<int, WidgetLibInfo> WidgetLibs { get { return m_widgetLibs; } }
        /// <summary>
        /// WidgetID到小工具实体的词典
        /// </summary>
        public Dictionary<int, UserControl> Controls { get { return m_controls; } }
        /// <summary>
        /// 返回当前是否在浏览自己拥有的空间
        /// </summary>
        public bool IsInMySpace { get { return MySpace.SpaceID == CurrentSpace.SpaceID; } }
        /// <summary>
        /// 获取当前的空间管理器
        /// </summary>
        internal SpaceManager CurrentSpaceManager { get { return m_spaceManager; } }

        #endregion

        #region private members
        private bool m_ready = false;
        private SystemSetting m_setting = new SystemSetting();
        private UserInfo m_myUserInfo = new UserInfo();
        private SpaceInfo m_mySpace = new SpaceInfo();
        private List<string> m_myFriends = new List<string>();
        private List<SysMessage> m_myMessages = new List<SysMessage>();
        private SpaceInfo m_currentSpace = new SpaceInfo();
        private Dictionary<int, WidgetInfo> m_currentWidgets = new Dictionary<int,WidgetInfo>();
        private Dictionary<int, WidgetLibInfo> m_widgetLibs = new Dictionary<int, WidgetLibInfo>();
        private Dictionary<int, UserControl> m_controls = new Dictionary<int, UserControl>();
        private List<int> m_dirtyWidgets = new List<int>();

        private int m_updateInterval = 10;
        private DispatcherTimer m_msgTimer = new DispatcherTimer();
        private DispatcherTimer m_widgetTimer = new DispatcherTimer();
        private Queue<WidgetInfo> m_widgetAddQueue = new Queue<WidgetInfo>();
        private Queue<int> m_widgetDelQueue = new Queue<int>();
        private Dictionary<string, Assembly> m_assemblies = new Dictionary<string, Assembly>();
        private SpaceManager m_spaceManager = new SpaceManager();
        #endregion

        #region singleton
        private static OperationManager m_instance = new OperationManager();
        public static OperationManager Instance { get { return m_instance; } }
        #endregion

        private OperationManager()
        {
            m_myUserInfo.UserID = "";
            m_myUserInfo.Realname = "";
            m_msgTimer.Interval = new TimeSpan(0, 0, m_updateInterval);
            m_widgetTimer.Interval = new TimeSpan(0, 0, m_updateInterval);
            m_msgTimer.Tick += AutoLoadInfos;
            m_widgetTimer.Tick += AutoSaveInfos;
        }

        #region factory methods
        /// <summary>
        /// 构建一个用于普通小工具的界面操控代理
        /// </summary>
        /// <param name="widget">小工具的引用</param>
        /// <returns>与参数widget对应的代理，失败返回null</returns>
        public WidgetSpaceProxy CreateWidgetSpaceProxy(UserControl widget)
        {
            ErrorManager.Instance.LogMessage("OperationManager::CreateWidgetServiceProxy", "Invoke");
            foreach (KeyValuePair<int, UserControl> uc in m_controls)
            {
                if (uc.Value == widget)
                {
                    return new WidgetSpaceProxy(uc.Key);
                }
            }
            ErrorManager.Instance.ShowDebugMessage("OperationManager::CreateWidgetServiceProxy Failed");
            return null;
        }

        /// <summary>
        /// 构建一个用于普通小工具的服务访问代理
        /// 小工具要访问Session应使用此代理
        /// </summary>
        /// <param name="widget">小工具的引用</param>
        /// <returns>与参数widget对应的代理，失败返回null</returns>
        public WidgetServiceProxy CreateWidgetServiceProxy(UserControl widget)
        {
            ErrorManager.Instance.LogMessage("OperationManager::CreateWidgetServiceProxy", "Invoke");
            foreach (KeyValuePair<int, UserControl> uc in m_controls)
            {
                if (uc.Value == widget)
                {
                    return new WidgetServiceProxy(uc.Key);
                }
            }
            ErrorManager.Instance.ShowDebugMessage("OperationManager::CreateWidgetServiceProxy Failed");
            return null;
        }

        #endregion

        #region global operations
        /// <summary>
        /// 初始化
        /// 自动更新SystemSetting，下载所有小工具
        /// </summary>
        internal void Init()
        {
            ErrorManager.Instance.LogMessage("OperationManager::Init", "Invoke");
            ServiceManager.Instance.GetSystemSetting(this);
            m_spaceManager.SetStatus(SpaceManager.STATUS_INIT);
        }

        /// <summary>
        /// 全局登陆
        /// 自动更新MyUserInfo, MySpace, MyMessage, MyFriend
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="password"></param>
        internal void Login(string userID, string password)
        {
            ErrorManager.Instance.LogMessage("OperationManager::Login", "Invoke");
            ServiceManager.Instance.Login(userID, password, this);
            MyUserInfo.UserID = userID;
        }

        /// <summary>
        /// 系统登出，清理相关的数据
        /// </summary>
        internal void Logout()
        {
            ErrorManager.Instance.LogMessage("OperationManager::Logout", "Invoke");
            AutoSaveInfos(null, null);
            m_spaceManager.SetStatus(SpaceManager.STATUS_INIT);
            m_controls.Clear();
            m_currentSpace.SpaceID = -1;
            m_currentWidgets.Clear();
            m_myFriends.Clear();
            m_myMessages.Clear();
            m_mySpace.SpaceID = -1;
            m_myUserInfo.UserID = "";
            m_widgetLibs.Clear();
            EnterSpace(m_setting.SystemUserID);
        }

        /// <summary>
        /// 进入指定空间
        /// 自动更新widgets，并调用SpaceManager
        /// </summary>
        /// <param name="ownerUserID"></param>
        internal void EnterSpace(string ownerUserID)
        {
            if (!Ready)
            {
                ErrorManager.Instance.ShowErrorMessage("系统尚未加载完成，不能进入空间，请稍等再重试");
                return;
            }
            ErrorManager.Instance.LogMessage("OperationManager::EnterSpace", "Invoke");
            ServiceManager.Instance.GetSpaceInfo(ownerUserID, this);
        }

        /// <summary>
        /// 设定个人用户信息
        /// </summary>
        /// <param name="userInfo">我的用户信息</param>
        internal void SetMyUserInfo(UserInfo userInfo, string password)
        {
            if (userInfo.UserID != m_myUserInfo.UserID)
            {
                ErrorManager.Instance.ShowDebugMessage("OperationManager::SetMyUserInfo fail!");
                return;
            }
            m_myUserInfo = userInfo;
            ServiceManager.Instance.SetUserInfo(userInfo, this);
            if(string.IsNullOrEmpty(password) == false)
                ServiceManager.Instance.SetPassword(userInfo.UserID, password, this);
        }

        /// <summary>
        /// 设定个人空间的信息
        /// 同时会更新界面
        /// </summary>
        /// <param name="spaceInfo">我的空间信息</param>
        internal void SetMySpaceInfo(SpaceInfo spaceInfo)
        {
            if (spaceInfo.SpaceID != m_mySpace.SpaceID)
            {
                ErrorManager.Instance.ShowDebugMessage("OperationManager::SetMySpace fail!");
                return;
            }
            m_mySpace = spaceInfo;
            ServiceManager.Instance.SetSpaceInfo(spaceInfo, this);
        }

        /// <summary>
        /// 增加一个小工具，与服务器同步
        /// </summary>
        /// <param name="widgetInfo"></param>
        internal void AddWidgetInfo(WidgetInfo widgetInfo)
        {
            m_widgetAddQueue.Enqueue(widgetInfo);
            if (m_widgetAddQueue.Count <= 1)
                ServiceManager.Instance.AddWidgetInfo(widgetInfo, this);
        }

        /// <summary>
        /// 更新一个工具的信息，并在一段时间后与服务器同步
        /// </summary>
        /// <param name="widgetInfo"></param>
        internal void SetWidgetInfo(int widgetID, int posX, int posY, int sizeX, int sizeY)
        {
            if (!IsInMySpace || m_currentWidgets.ContainsKey(widgetID) == false)
                return;
            m_currentWidgets[widgetID].PosX = posX;
            m_currentWidgets[widgetID].PosX = posY;
            m_currentWidgets[widgetID].Width = sizeX;
            m_currentWidgets[widgetID].Height = sizeY;
            if(m_dirtyWidgets.Contains(widgetID) == false)
                m_dirtyWidgets.Add(widgetID);
        }

        internal void DelWidgetInfo(int widgetID)
        {
            m_widgetDelQueue.Enqueue(widgetID);
            if (m_widgetDelQueue.Count <= 1)
                ServiceManager.Instance.DelWidgetInfo(m_mySpace.SpaceID, widgetID, this);
        }
        #endregion

        #region auto update methods
        internal void BeginUpdateMessages()
        {
            ErrorManager.Instance.LogMessage("OperationManager::BeginUpdateMessages", "Invoke");
            m_msgTimer.Start();
        }

        internal void BeginUpdateWidgets()
        {
            ErrorManager.Instance.LogMessage("OperationManager::BeginUpdateWidgets", "Invoke");
            m_widgetTimer.Start();
        }
        #endregion

        #region private methods
        private UserControl CreateLibAndControl(WidgetInfo widgetInfo)
        {
            ErrorManager.Instance.LogMessage("OperationManager::CreateUserControl", "Invoke");

            //update widgetlib
            foreach (WidgetLibInfo wli in Setting.WidgetLibList)
            {
                if (wli.ID == widgetInfo.WidgetLibInfoID)
                {
                    m_widgetLibs.Add(widgetInfo.WidgetID, wli);
                    break;
                }
            }

            if (m_controls.ContainsKey(widgetInfo.WidgetID))// if it's existed
            {
                return m_controls[widgetInfo.WidgetID];
            }
            else
            {
                if (m_widgetLibs.ContainsKey(widgetInfo.WidgetID) == false)
                {
                    ErrorManager.Instance.ShowDebugMessage("OperationManager::CreateControl failed! not found in libs");
                    return null;
                }
                string url = Setting.WidgetFolderUrl
                    + WidgetLibs[widgetInfo.WidgetID].WidgetFileName;
                if (m_assemblies.ContainsKey(url))
                {
                    UserControl uc = m_assemblies[url].CreateInstance(
                        WidgetLibs[widgetInfo.WidgetID].WidgetAssemblyName) as UserControl;
                    m_controls.Add(widgetInfo.WidgetID, uc);
                    return uc;
                }
            }
            ErrorManager.Instance.ShowDebugMessage("OperationManager::CreateControl failed!");
            return null;
        }
        #endregion

        #region auto update implements
        internal void AutoLoadInfos(object sender, EventArgs e)
        {
            //update message list
            ServiceManager.Instance.GetMessageList(MyUserInfo.UserID, this);
        }

        internal void AutoSaveInfos(object sender, EventArgs e)
        {
            //update widgets if in myspace
            if (!IsInMySpace)
                return;
            foreach (int i in m_dirtyWidgets)
            {
                ServiceManager.Instance.UpdateWidgetInfo(m_currentWidgets[i], this);
            }
            m_dirtyWidgets.Clear();
        }
        #endregion

        #region implement listeners
        // system listener
        public void OnLogin(LoginCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnLogin", "Event");
            if (e.Result == true)
            {
                EnterSpace(MyUserInfo.UserID);
                ServiceManager.Instance.GetUserInfo(MyUserInfo.UserID, this);
                ServiceManager.Instance.GetMessageList(MyUserInfo.UserID, this);
                ServiceManager.Instance.GetFriendList(MyUserInfo.UserID, this);
            }
            else
            {
                ErrorManager.Instance.ShowErrorMessage("登陆失败");
                ErrorManager.Instance.ShowLastServiceError();
                MyUserInfo.UserID = "";
            }
        }
        public void OnRegister(RegisterCompletedEventArgs e) { }
        public void OnGetSystemSetting(GetSystemSettingCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnSystemSetting", "Event");
            if (e.Result == null)
            {
                ErrorManager.Instance.ShowErrorMessage("系统信息读取失败！");
                ErrorManager.Instance.ShowLastServiceError();
                return;
            }
            m_setting = e.Result;
            //load assemblies
            List<string> urls = new List<string>();
            string folder = m_setting.WidgetFolderUrl;
            if (m_setting.WidgetLibList == null)
                m_setting.WidgetLibList = new System.Collections.ObjectModel.ObservableCollection<WidgetLibInfo>();
            foreach (WidgetLibInfo wli in m_setting.WidgetLibList)
            {
                if (urls.Contains(folder + wli.WidgetFileName) == false)
                    urls.Add(folder + wli.WidgetFileName);
            }
            foreach (string u in urls)
            {
                m_assemblies.Add(u, null);
                ServiceManager.Instance.LoadFile(u, this);
            }
        }
        //user listener
        public void OnGetUserInfo(GetUserInfoCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnGetUserInfo", "Event");
            if (e.Result == null)
            {
                ErrorManager.Instance.ShowErrorMessage("用户信息读取失败");
                ErrorManager.Instance.ShowLastServiceError();
            }
            else if (e.Result.UserID == MyUserInfo.UserID)
                m_myUserInfo = e.Result;
        }
        public void OnSetUserInfo(SetUserInfoCompletedEventArgs e)
        {
            if (e.Result == false)
            {
                ErrorManager.Instance.ShowErrorMessage("用户信息更新失败");
                ErrorManager.Instance.ShowLastServiceError();
            }
        }
        public void OnSetPassword(SetPasswordCompletedEventArgs e)
        {
            if (e.Result == false)
            {
                ErrorManager.Instance.ShowErrorMessage("密码修改失败");
                ErrorManager.Instance.ShowLastServiceError();
            }
        }
        //space listener
        public void OnGetSpaceInfo(GetSpaceInfoCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnGetSpaceInfo", "Event");
            if (e.Result == null)
            {
                ErrorManager.Instance.ShowErrorMessage("空间数据读取失败！");
                ErrorManager.Instance.ShowLastServiceError();
                return;
            }
            m_currentSpace = e.Result;
            if (e.Result.OwnerUserID == m_myUserInfo.UserID)
            {
                m_mySpace = e.Result;
                m_spaceManager.SetStatus(SpaceManager.STATUS_MYSPACE);
            }
            else if(e.Result.OwnerUserID == m_setting.SystemUserID)
            {
                // do nothing
            }
            else
                m_spaceManager.SetStatus(SpaceManager.STATUS_NOT_MYSPACE);
            ServiceManager.Instance.GetWidgetList(e.Result.SpaceID, this);
        }
        public void OnSetSpaceInfo(SetSpaceInfoCompletedEventArgs e)
        {
            if (e.Result == false)
            {
                ErrorManager.Instance.ShowErrorMessage("空间信息更新失败！");
                ErrorManager.Instance.ShowLastServiceError();
            }
            //更新界面
            m_spaceManager.SetStatus(SpaceManager.STATUS_MYSPACE);
        }
        //message listener
        public void OnSendMessage(SendMessageCompletedEventArgs e) { }
        public void OnGetMessageList(GetMessageListCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnGetMessageList", "Event");
            if (e.Result == null)
            {
                ErrorManager.Instance.ShowDebugMessage("信息列表读取失败");
                return;
            }
            MyMessages.Clear();
            foreach (SysMessage m in e.Result)
                MyMessages.Add(m);
        }
        //widget listener
        public void OnGetWidgetList(GetWidgetListCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnGetWidgetList", "Event");
            if(e.Result == null)
            {
                ErrorManager.Instance.ShowDebugMessage("信息列表读取失败");
                return;
            }
            m_currentWidgets.Clear();
            m_controls.Clear();
            m_widgetLibs.Clear();
            m_spaceManager.ClearWidgets();
            foreach (WidgetInfo wi in e.Result)
            {
                m_currentWidgets.Add(wi.WidgetID, wi);
                CreateLibAndControl(wi);
                m_spaceManager.SetWidget(wi, m_controls[wi.WidgetID]);
            }
            if (IsInMySpace)
            {
            }
        }
        public void OnAddWidgetInfo(AddWidgetInfoCompletedEventArgs e)
        {
            if (m_widgetAddQueue.Count == 0)
            {
                ErrorManager.Instance.ShowDebugMessage("OperationManager::OnAddWidget add queue is empty!");
                return;
            }
            WidgetInfo wi = m_widgetAddQueue.Dequeue();
            if (e.Result == -1)//fail
            {
                ErrorManager.Instance.ShowErrorMessage("新建小工具失败");
                ErrorManager.Instance.ShowLastServiceError();
            }
            else
            {
                wi.WidgetID = e.Result;
                m_currentWidgets.Add(wi.WidgetID, wi);
                CreateLibAndControl(wi);
                m_spaceManager.SetWidget(wi, m_controls[wi.WidgetID]);
            }

            if (m_widgetAddQueue.Count > 0) // still have some to add
                ServiceManager.Instance.AddWidgetInfo(m_widgetAddQueue.Peek(), this);
        }
        public void OnDeleteWidgetInfo(DeleteWidgetInfoCompletedEventArgs e)
        {
            if (m_widgetDelQueue.Count == 0)
            {
                ErrorManager.Instance.ShowDebugMessage("OperationManager::OnDelWidget del queue is empty!");
                return;
            }
            int widgetID = m_widgetDelQueue.Dequeue();
            if (e.Result == false)//fail
            {
                ErrorManager.Instance.ShowErrorMessage("删除小工具失败");
                ErrorManager.Instance.ShowLastServiceError();
            }
            else
            {
                m_spaceManager.SetWidget(m_currentWidgets[widgetID], null);

                m_currentWidgets.Remove(widgetID);
                m_controls.Remove(widgetID);
                m_widgetLibs.Remove(widgetID);
            }

            if (m_widgetDelQueue.Count > 0) // still have some to del
                ServiceManager.Instance.DelWidgetInfo(m_mySpace.SpaceID, m_widgetDelQueue.Peek(), this);
        }
        public void OnUpdateWidgetInfo(UpdateWidgetInfoCompletedEventArgs e) { }
        //friend listener
        public void OnGetFriendList(GetFriendListCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnGetFriendList", "Event");
            if (e.Result == null)
            {
                ErrorManager.Instance.ShowDebugMessage("好友列表读取失败！");
                return;
            }
            MyFriends.Clear();
            foreach (string f in e.Result)
                MyFriends.Add(f);
        }
        public void OnAddFriend(AddFriendCompletedEventArgs e) { }
        public void OnDelFriend(DelFriendCompletedEventArgs e) { }
        //file listener
        public void OnLoadFile(OpenReadCompletedEventArgs e)
        {
            ErrorManager.Instance.LogMessage("OperationManager::OnLoadFile", "Event");
            //load assemblies
            Stream stream = Application.GetResourceStream(
                new StreamResourceInfo(e.Result, null),
                new Uri("AppManifest.xaml", UriKind.Relative)).Stream;

            String appManifestString = new StreamReader(stream).ReadToEnd();

            Deployment deployment = (Deployment)XamlReader.Load(appManifestString);

            Assembly assembly = null;
            foreach (AssemblyPart assemblyPart in deployment.Parts)
            {
                string[] strs = e.Address.ToString().Split(new char[1] { '/' });
                string name = strs[strs.Length - 1];
                if (assemblyPart.Source == name.Substring(0, name.Length - 3) + "dll")
                {
                    String source = assemblyPart.Source;

                    StreamResourceInfo streamInfo = Application.GetResourceStream(
                        new StreamResourceInfo(e.Result,
                        "application/binary"),
                        new Uri(source, UriKind.Relative));

                    assembly = assemblyPart.Load(streamInfo.Stream);
                    break;
                }
            }

            m_assemblies[e.Address.ToString()] = assembly;

            // check if it is all loaded
            bool isFinish = true;
            foreach (Assembly a in m_assemblies.Values)
            {
                if (a == null)
                {
                    isFinish = false;
                    break;
                }
            }
            // if it's done, set ready and enter system space
            if (isFinish)
            {
                m_ready = true;
                EnterSpace(m_setting.SystemUserID);
            }
        }
        public void OnSaveFile(OpenWriteCompletedEventArgs e) { }//do nothing
        #endregion
    }
}
